package ai.turbochain.ipex.controller;

import ai.turbochain.ipex.annotation.AccessLog;
import ai.turbochain.ipex.constant.AdminModule;
import ai.turbochain.ipex.constant.CommonStatus;
import ai.turbochain.ipex.constant.MemberRegisterOriginEnum;
import ai.turbochain.ipex.constant.SysConstant;
import ai.turbochain.ipex.controller.BaseController;
import ai.turbochain.ipex.entity.Admin;
import ai.turbochain.ipex.entity.Member;
import ai.turbochain.ipex.entity.Sign;
import ai.turbochain.ipex.entity.transform.AuthMember;
import ai.turbochain.ipex.event.MemberEvent;
import ai.turbochain.ipex.service.AdminService;
import ai.turbochain.ipex.service.LocaleMessageSourceService;
import ai.turbochain.ipex.service.MemberService;
import ai.turbochain.ipex.service.SignService;
import ai.turbochain.ipex.util.CaptchaUtil;
import ai.turbochain.ipex.util.Md5;
import ai.turbochain.ipex.util.MessageResult;
import com.sparkframework.lang.Convert;
import com.sparkframework.security.Encrypt;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.SessionAttribute;

import ai.turbochain.ipex.entity.LoginInfo;
import ai.turbochain.ipex.system.GeetestLib;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import static ai.turbochain.ipex.constant.SysConstant.SESSION_MEMBER;
import static org.springframework.util.Assert.hasText;
import static org.springframework.util.Assert.notNull;

import java.util.Calendar;
import java.util.HashMap;

/**
 * @author jack
 * @date 2018年01月10日
 */
@RestController
@Slf4j
public class LoginController extends BaseController {

    @Autowired
    private MemberService memberService;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private MemberEvent memberEvent;
    @Autowired
    private LocaleMessageSourceService messageSourceService;
    @Autowired
    private GeetestLib gtSdk;
    @Autowired
    private SignService signService;
    @Value("${person.promote.prefix:}")
    private String promotePrefix;
    
    
    @RequestMapping(value = "/login")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult login(HttpServletRequest request, String username, String password, String emailCode) {
//        Assert.hasText(username, messageSourceService.getMessage("MISSING_USERNAME"));
//        Assert.hasText(password, messageSourceService.getMessage("MISSING_PASSWORD"));
//        Assert.hasText(emailCode, messageSourceService.getMessage("MISSING_VERIFICATION_CODE"));
        // 判断用户名
        if (StringUtils.isBlank(username)) {
            return error("MISSING_USERNAME");
        }
        // 判断密码
        if (StringUtils.isBlank(password)) {
            return error("MISSING_PASSWORD");
        }
        // 判断邮箱验证码
        if (StringUtils.isBlank(emailCode)) {
             return error("MISSING_VERIFICATION_CODE");
        }
        // 查询redis
        ValueOperations valueOperations = redisTemplate.opsForValue();
//        // 邮箱验证码缓存
        Object cache = valueOperations.get(SysConstant.EMAIL_LOGIN_CODE_PREFIX  + username);
        if (null == cache || !emailCode.equals(cache.toString())) {
            return MessageResult.error(messageSourceService.getMessage("VERIFICATION_CODE_INCORRECT"));
        } else {
            valueOperations.getOperations().delete(SysConstant.EMAIL_LOGIN_CODE_PREFIX + username);
        }
        String ip = getRemoteIp(request);
        String challenge = request.getParameter(GeetestLib.fn_geetest_challenge);
        String validate = request.getParameter(GeetestLib.fn_geetest_validate);
        String seccode = request.getParameter(GeetestLib.fn_geetest_seccode);
        //兼容没有极验证
        if (challenge == null && validate == null && seccode == null) {
            try {
                LoginInfo loginInfo = getLoginInfo(username, password, ip, request);
                return success(loginInfo);
            } catch (Exception e) {
                return error(e.getMessage());
            }
        }
        //从session中获取gt-server状态
        int gt_server_status_code = (Integer) request.getSession().getAttribute(gtSdk.gtServerStatusSessionKey);
        //从session中获取userid
        String userid = (String) request.getSession().getAttribute("userid");
        //自定义参数,可选择添加
        HashMap<String, String> param = new HashMap<String, String>();
        param.put("user_id", userid); //网站用户id
        param.put("client_type", "web"); //web:电脑上的浏览器；h5:手机上的浏览器，包括移动应用内完全内置的web_view；native：通过原生SDK植入APP应用的方式
        param.put("ip_address", ip); //传输用户请求验证时所携带的IP

        int gtResult = 0;

        if (gt_server_status_code == 1) {
            //gt-server正常，向gt-server进行二次验证
            gtResult = gtSdk.enhencedValidateRequest(challenge, validate, seccode, param);
            //System.out.println(gtResult);
        } else {
            // gt-server非正常情况下，进行failback模式验证
            System.out.println("failback:use your own server captcha validate");
            gtResult = gtSdk.failbackValidateRequest(challenge, validate, seccode);
            // System.out.println(gtResult);
        }
        if (gtResult == 1) {
            // 验证成功
            try {
                LoginInfo loginInfo = getLoginInfo(username, password, ip, request);
                
                return success(loginInfo);
            } catch (Exception e) {
                return error(e.getMessage());
            }
        } else {
            // 验证失败
            return error(messageSourceService.getMessage("GEETEST_FAIL"));
        }
    }

    @RequestMapping(value = "/check")
    @ResponseBody
    public MessageResult checkEmailCode(String username, String password, HttpServletRequest request) throws Exception {
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return error("用户名或密码不能为空");
        }
        Member member = memberService.findByEmailAndOrigin(username,MemberRegisterOriginEnum.IPEX.getSourceType());
        if (member == null) {
            return error("用户名不存在，请先注册");
        } else if (!Md5.md5Digest(password + member.getSalt()).toLowerCase().equals(member.getPassword())){
            return error("用户名或密码错误");
        } else if (member.getStatus().equals(CommonStatus.ILLEGAL)) {
            return error("该帐号处于未激活/禁用状态，请联系客服");
        } else {
            try {
                request.getSession().setAttribute("username",username);
                request.getSession().setAttribute("password",password);
                request.getSession().setAttribute("phone",member.getEmail());
                return success(member.getEmail());
            } catch (Exception e) {
                e.printStackTrace();
            }
            return success("验证码发送或保存失败");
        }
    }

    /**
     * 
     * @param username
     * @param password
     * @param ip
     * @param request
     * @return
     * @throws Exception
     */
    private LoginInfo getLoginInfo(String username, String password, String ip, HttpServletRequest request) throws Exception {
        Member member = memberService.login(username, password);
       
        // 只允许IPEX注册用户登录
        if (member.getOrigin()!=MemberRegisterOriginEnum.IPEX.getSourceType()) {
        	return null;
        }
        
        memberEvent.onLoginSuccess(member, ip);
        
        // 处理登录成功Session
        request.getSession().setAttribute(SysConstant.SESSION_MEMBER, AuthMember.toAuthMember(member));
       
        String token = request.getHeader("access-auth-token");
        if (!StringUtils.isBlank(token)) {
            member.setToken(token);
        }
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.HOUR_OF_DAY, 24 * 7);
        member.setTokenExpireTime(calendar.getTime());
        //获取登录次数
        int loginCount = member.getLoginCount();
        member.setLoginCount(loginCount+1);
        // 签到活动是否进行
        Sign sign = signService.fetchUnderway();
        LoginInfo loginInfo;
        if (sign == null) {
            loginInfo = LoginInfo.getLoginInfo(member, request.getSession().getId(), false,promotePrefix);
        } else {
            loginInfo = LoginInfo.getLoginInfo(member, request.getSession().getId(), true,promotePrefix);
        }
       return loginInfo;
    }

    /**
     *	 登出
     *
     * @return
     */
    @RequestMapping(value = "/loginout")
    @Transactional(rollbackFor = Exception.class)
    public MessageResult loginOut(HttpServletRequest request, @SessionAttribute(SESSION_MEMBER) AuthMember user) {
        MessageResult messageResult = new MessageResult();
        log.info(">>>>>退出登陆接口开始>>>>>");
        try {
            request.getSession().removeAttribute(SysConstant.SESSION_MEMBER);
            Member member = memberService.findOne(user.getId());
            member.setToken(null);
            messageResult= request.getSession().getAttribute(SysConstant.SESSION_MEMBER) != null ? error(messageSourceService.getMessage("LOGOUT_FAILED")) : success(messageSourceService.getMessage("LOGOUT_SUCCESS"));
        } catch (Exception e) {
            e.printStackTrace();
            log.info(">>>>>登出失败>>>>>"+e);
        }
        log.info(">>>>>退出登陆接口结束>>>>>");
        return messageResult;
    }

    /**
     *	 检查是否登录
     *
     * @param request
     * @return
     */
    @RequestMapping("/check/login")
    public MessageResult checkLogin(HttpServletRequest request) {
        AuthMember authMember = (AuthMember) request.getSession().getAttribute(SESSION_MEMBER);
        MessageResult result = MessageResult.success();
        if (authMember != null) {
            result.setData(true);
        } else {
            result.setData(false);
        }
        return result;
    }
}
